﻿/******************************************************************************
 * 【本类功能概述】                                 					      *
 *  版权所有（C）2017- 匠梦科技                                         *
 *  保留所有权利。                                                            *
 ******************************************************************************
 *  作者 : <hughjk>
 *  创建时间:2019年5月19日 14:59:28
 *  文件描述:扩展代码
 *****************************************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Util
{
    public static class MathTool
    {
        public static int toAbs(this int s)
        {
            return Mathf.Abs(s);
        }

        public static float toAbs(this float s)
        {
            return Mathf.Abs(s);
        }

        public static int toInt(this int s)
        {
            return s;
        }

        public static uint toUint(this int s)
        {
            return (uint)s;
        }

        public static int toInt(this Enum e)
        {
            return e.GetHashCode();
        }

        public static long toLong(this Enum e)
        {
            return (long)(object)e;
        }

        public static int toInt(this float s)
        {
            return (int)s;
        }

        public static long toLong(this float s)
        {
            return (long)s;
        }

        public static float toFloat(this int s)
        {
            return (float)s;
        }

        public static Vector2 toAddX(this Vector2 vector, float x)
        {
            return new Vector2(vector.x + x, vector.y);
        }

        public static Vector2 toAddY(this Vector2 vector, float y)
        {
            return new Vector2(vector.x, vector.y + y);
        }

        public static Vector2 toSetX(this Vector2 vector, float x)
        {
            return new Vector2(x, vector.y);
        }

        public static Vector2 toSetY(this Vector2 vector, float y)
        {
            return new Vector2(vector.x, y);
        }

        public static Vector2 toMulX(this Vector2 vector, float x)
        {
            return new Vector2(vector.x * x, vector.y);
        }

        public static Vector2 toMulY(this Vector2 vector, float y)
        {
            return new Vector2(vector.x, vector.y * y);
        }

        public static Vector3 toVector3(this Vector2 vector)
        {
            return new Vector3(vector.x, vector.y);
        }

        public static T toEnum<T>(this int eunm)
        {
            T t = default(T);
            try
            {
                t = (T)(Enum.ToObject(typeof(T), eunm));
            }
            catch (System.Exception)
            {
                //debug.log("转枚举类似错误!!", eunm, typeof(T));
            }
            return t;
        }

        /// <summary>
        /// 二进制的标记 判断A是否包含B标记
        /// </summary>
        public static bool to2TagIn(this int a, int b)
        {
            if ((a & b) == b)
            {
                return true;
            }
            return false;
        }

        public static int toClamp(this int v, int min, int max)
        {
            return Mathf.Clamp(v, min, max);
        }

        public static float toClamp(this float v, float min, float max)
        {
            return Mathf.Clamp(v, min, max);
        }

        public static Vector2 toClamp(this Vector2 v, Vector2 min, Vector2 max)
        {
            v.x = Mathf.Clamp(v.x, min.x, max.x);
            v.y = Mathf.Clamp(v.y, min.y, max.y);
            return v;
        }

        public static Vector3 toClamp(this Vector3 v, Vector3 min, Vector3 max)
        {
            v.x = Mathf.Clamp(v.x, min.x, max.x);
            v.y = Mathf.Clamp(v.y, min.y, max.y);
            v.z = Mathf.Clamp(v.z, min.z, max.z);
            return v;
        }

        public static Vector3 toRandRange(this Vector3 v)
        {
            v.x = Random.Range(-v.x, v.x);
            v.y = Random.Range(-v.y, v.y);
            v.z = Random.Range(-v.z, v.z);
            return v;
        }

        public static bool toIsIn(this float v, float min, float max)
        {
            if (v > min && v < max)
            {
                return true;
            }
            return false;
        }

        public static bool toIsIn(this Vector3 v, Vector3 min, Vector3 max)
        {
            if (v.x >= min.x &&
                v.y >= min.y &&
                v.z >= min.z &&
                v.x <= max.x &&
                v.y <= max.y &&
                v.z <= max.z
                )
            {
                return true;
            }

            return false;
        }

        //世界位置是否在屏幕内
        public static bool toWorldPosIsInScreen(this Vector3 v)
        {
            Vector3 ScreenPos = Camera.main.WorldToScreenPoint(v);
            if (ScreenPos.toScreenPosIsInScreen())
            {
                return true;
            }
            return false;
        }

        //屏幕位置是否在屏幕内
        public static bool toScreenPosIsInScreen(this Vector3 v)
        {
            Vector3 ScreenSee = new Vector3(Screen.width, Screen.height, v.z);
            if (v.toIsIn(Vector3.zero, ScreenSee))
            {
                return true;
            }
            return false;
        }

        //屏幕位置转为屏幕内位置
        public static Vector3 toScreenInPos(this Vector3 v)
        {
            Vector3 ScreenSee = new Vector3(Screen.width, Screen.height, v.z);
            ScreenSee = v.toClamp(Vector3.zero, ScreenSee);
            return ScreenSee;
        }

        //屏幕位置转为屏幕内的世界位置
        public static Vector3 toScreenInWorldPos(this Vector3 v)
        {
            v = v.toScreenInPos();
            v = Camera.main.ScreenToWorldPoint(v);
            return v;
        }

        public static Vector3 toWorlPosToScreenInToWorldPos(this Vector3 v)
        {
            v = Camera.main.WorldToScreenPoint(v);
            v = v.toScreenInPos();
            v = Camera.main.ScreenToWorldPoint(v);
            return v;
        }

        public static Vector3 toWorlPosToScreenInPos(this Vector3 v)
        {
            v = Camera.main.WorldToScreenPoint(v);
            v = v.toScreenInPos();
            return v;
        }

        public static float to2dDistanceSquare(this Vector3 v, Vector3 endpos)
        {
            float dis = (v.x - endpos.x) * (v.x - endpos.x) + (v.y - endpos.y) * (v.y - endpos.y);
            return dis;
        }

        //计算射线,在X平面上的位置
        public static Vector3 toZPlanePos(this Ray ray, float z = 0)
        {
            Vector3 vector = ray.origin;
            Vector3 dir = ray.direction;
            Vector3 pos = ray.origin;
            float a = (z - pos.z) / dir.z;
            vector.x = pos.x + dir.x * a;
            vector.y = pos.y + dir.y * a;
            vector.z = z;
            return vector;
        }

        /// <summary>
        /// 概率幸运抽奖
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLucky<T>(this List<T> v)
        {
            T cur = default(T);
            if (v != null)
            {
                cur = v.ToArray().toLucky();
            }
            return cur;
        }

        /// <summary>
        /// 概率幸运抽奖
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLucky<T>(this T[] v)
        {
            T cur = default(T);
            if (v != null)
            {
                if (v.Length == 1)
                {
                    cur = v[0];
                }
                else if (v.Length > 1)
                {
                    int rand = UnityEngine.Random.Range(0, v.Length);
                    cur = v[rand];
                }
            }
            return cur;
        }

        /// <summary>
        /// 区间随机 数组1位3=>3,或者2位,2位取两者的区间,3-4=>3.5
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static float toExtent(this List<float> v)
        {
            float cur = -1;
            if (v != null)
            {
                if (v.Count == 1)
                {
                    cur = v[0];
                }
                else if (v.Count == 2)
                {
                    cur = UnityEngine.Random.Range(v[0], v[1]);
                }
            }
            return cur;
        }

        /// <summary>
        /// 最后一位
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="v"></param>
        /// <returns></returns>
        public static T toLastOneData<T>(this List<T> v)
        {
            T cur = default(T);
            if (v.Count >= 1)
            {
                return v[v.Count - 1];
            }
            return cur;
        }

        /// <summary>
        /// 判断两个点的距离小于某个值
        /// </summary>
        public static bool toPosLTDic(this Vector3 pos1, Vector3 pos2, float dic)
        {
            return dic * dic > (pos1 - pos2).sqrMagnitude;
        }

        /// <summary>
        /// 判断两个点的距离小于某个值
        /// </summary>
        public static bool toPosLTDic(this Vector2 pos1, Vector2 pos2, float dic)
        {
            return dic * dic > (pos1 - pos2).sqrMagnitude;
        }

        public static Transform toPosMinDis(this Transform v, List<Component> list)
        {
            List<Transform> rf = new List<Transform>();
            for (int i = 0; i < list.Count; i++)
            {
                rf.Add(list[i].transform);
            }
            return v.toPosMinDis(rf);
        }

        //距离当前对象位置最近的一个
        public static Transform toPosMinDis(this Transform v, List<Transform> list)
        {
            float dis = int.MaxValue;
            Transform cv = v;
            for (int i = 0; i < list.Count; i++)
            {
                if (v != list[i])
                {
                    float cdis = (v.position - list[i].position).sqrMagnitude;
                    if (cdis < dis)
                    {
                        dis = cdis;
                        cv = list[i];
                    }
                }
            }
            return cv;
        }

        /// <summary>
        /// 保留几位小数 没有四折五入
        /// </summary>
        public static float toRound(this float s, int num)
        {
            if (s == 0)
            {
                return 0;
            }
            if (num > 0)
            {
                float b = Mathf.Pow(10, num);
                float vs = s * b;
                long iv = (long)vs;
                s = iv / b;
            }
            return s;
        }

        /// <summary>
        /// 保留几位小数 有四折五入
        /// </summary>
        public static float toRounds(this float s, int num)
        {
            if (s == 0)
            {
                return 0;
            }
            s = (float)Math.Round((double)s, num);
            return s;
        }

        /// <summary>
        /// 保留几位小数 有四折五入
        /// </summary>
        public static Vector3 toRounds(this Vector3 s, int num)
        {
            if (s == Vector3.zero)
            {
                return Vector3.zero;
            }
            s.x = (float)Math.Round((double)s.x, num);
            s.y = (float)Math.Round((double)s.y, num);
            s.z = (float)Math.Round((double)s.z, num);
            return s;
        }

        /// <summary>
        /// 去除精度
        /// </summary>
        public static float toRemoveAccuracy(this float s, float acc = 0.001f)
        {
            if (s < acc && s > -acc)
            {
                s = 0;
            }
            return s;
        }

        /// <summary>
        /// 去除精度
        /// </summary>
        public static Vector3 toRemoveAccuracy(this Vector3 s)
        {
            s.x = s.x.toRound(2);
            s.y = s.y.toRound(2);
            s.z = s.z.toRound(2);
            return s;
        }

        public static Mlist<Vector2> toVector2(this Mlist<Vector3> s)
        {
            return s.toList((t) => { return t.toVector2(); });
        }

        public static Vector2 toVector2(this Vector3 s)
        {
            s.z = 0;
            return s;
        }

        public static Vector2 Add(this Vector3 s, Vector2 add)
        {
            s.x += add.x;
            s.y += add.y;
            return s;
        }

        public static Vector3 Add(this Vector3 s, Vector3 add)
        {
            s.x += add.x;
            s.y += add.y;
            return s;
        }

        /// <summary>
        /// 取其中的几位列如:123456.setSub(2,2);=&gt;34
        /// </summary>
        public static int sub(this int num, int str, int len)
        {
            if (len == 0)
            {
                return 0;
            }
            int newNum = num;
            int zlen = newNum.Length();
            int zend = zlen - str - len;
            zend = zend < 0 ? 0 : zend;
            if (zend > zlen)
            {
                //debug.log("超过截取范围!!!!");
                return 0;
            }
            newNum /= (int)Math.Pow(10, zend);
            newNum %= (int)Math.Pow(10, len);
            return newNum;
        }

        /// <summary>
        /// 替换其中的几位,列如:123456.setSub(2,78);=&gt;127856
        /// </summary>
        public static int setSub(this int num, int str, int news)
        {
            int mlen = num.Length();
            int nlen = news.Length();
            int zend = mlen - str - nlen;
            zend = zend < 0 ? 0 : zend;
            int baseDigit = (int)Math.Pow(10, zend);
            int dislodge = num.sub(str, nlen) * baseDigit;//抹去位的值
            news *= baseDigit;//得到位

            num = num - dislodge + news;
            return num;
        }

        /// <summary>
        /// 获取一个整形的位长度
        /// </summary>
        public static int Length(this int num)
        {
            int zlen = 0;
            float u = num;
            for (int i = 0; i < 99; i++)
            {
                if (u < 1)
                {
                    break;
                }
                u = u / 10;
                zlen++;
            }
            return zlen;
        }

        /// <summary>
        /// 在这个只区间内随机
        /// </summary>
        /// <param name="vector"></param>
        /// <returns></returns>
        public static Vector2 toRandom(this Vector2 vector)
        {
            Vector2 pos = new Vector2();
            pos.x = Random.Range(0, vector.x);
            pos.y = Random.Range(0, vector.y);
            return pos;
        }

        /// <summary>
        /// 范围内随机一个点
        /// </summary>
        /// <param name="box"></param>
        /// <returns></returns>
        public static Vector3 toRandomInPos(this BoxCollider2D box)
        {
            Vector3 pos = (box.size.toRandom() + box.offset).toVector3() + box.transform.position;
            return pos;
        }

        //public static List<Vector3> toRandomInPos(this BoxCollider2D box, float R, int Num)
        //{
        //    List<Vector3> vectors = new List<Vector3>();
        //    float rs = R / 2;
        //    int xl = (box.size.x / rs).toInt();
        //    int yl = (box.size.y / rs).toInt();
        //    for (int i = 0; i <= xl; i++)
        //    {
        //        for (int j = 0; j <= yl; j++)
        //        {
        //            Vector3 pos = new Vector3();
        //            pos.x = i * rs + box.offset.x - box.size.x / 2 + box.transform.position.x + Random.Range(-rs, rs);
        //            pos.y = j * rs + box.offset.y - box.size.y / 2 + box.transform.position.y + Random.Range(-rs, rs);
        //            vectors.Add(pos);
        //        }
        //    }
        //    vectors.RandomizeList();
        //    if (Num < vectors.Count)
        //    {
        //        vectors.RemoveRange(Num, vectors.Count - Num);
        //    }
        //    return vectors;
        //}

        /// <summary>
        /// 最大数量的内包含圆
        /// </summary>
        /// <param name="box"></param>
        /// <param name="R"></param>
        /// <returns></returns>
        public static int toMaxInCircle(this BoxCollider2D box, float R)
        {
            int MaxNum = (int)(box.size.x / R) * (int)(box.size.y / R);
            return MaxNum;
        }

        /// <summary>
        /// 判断一个多边形里面大楷有多少圆
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="R"></param>
        /// <returns></returns>
        public static int toMaxInCircle(this PolygonCollider2D polygon, float R)
        {
            int MaxNum = (polygon.toArea() / CircleArea(R)).toInt();
            MaxNum = MaxNum > 1 ? MaxNum - 1 : MaxNum;
            return MaxNum;
        }

        /// <summary>
        /// 矩形的面积
        /// </summary>
        /// <param name="box"></param>
        /// <returns></returns>
        public static float toArea(this BoxCollider2D box)
        {
            float Area = 0;
            Area = box.size.x * box.size.y;
            return Area;
        }

        /// <summary>
        /// 多边形的面积
        /// </summary>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public static float toArea(this PolygonCollider2D polygon)
        {
            float Area = 0;
            for (int i = 0; i < polygon.pathCount; i++)
            {
                var pos = polygon.GetPath(i);
                Area += PolygonArea(pos);
            }
            return Area;
        }

        /// <summary>
        /// 计算多边形面积的函数
        /// (以原点为基准点,分割为多个三角形)
        /// 定理：任意多边形的面积可由任意一点与多边形上依次两点连线构成的三角形矢量面积求和得出。矢量面积=三角形两边矢量的叉乘。
        /// </summary>
        /// <param name="vectorPoints"></param>
        /// <returns></returns>
        public static float PolygonArea(Vector2[] vectorPoints)
        {
            int iCycle, iCount;
            iCycle = 0;
            float iArea = 0;
            iCount = vectorPoints.Length;

            for (iCycle = 0; iCycle < iCount; iCycle++)
            {
                iArea = iArea + (vectorPoints[iCycle].x * vectorPoints[(iCycle + 1) % iCount].y - vectorPoints[(iCycle + 1) % iCount].x * vectorPoints[iCycle].y);
            }

            return (float)Math.Abs(0.5 * iArea);
        }

        /// <summary>
        /// 计算圆的面积
        /// </summary>
        /// <param name="R"></param>
        /// <returns></returns>
        public static float CircleArea(float R)
        {
            return (float)(Math.PI * R * R);
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static float toLine(this float a, float b, float speed)
        {
            speed = Mathf.Abs(speed);
            float qv;
            if (a < b)
            {
                qv = a + speed;
                if (qv > b)
                {
                    qv = b;
                }
            }
            else
            {
                qv = a - speed;
                if (qv < b)
                {
                    qv = b;
                }
            }
            return qv;
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static Vector2 toLine(this Vector2 m, Vector2 v, float speed)
        {
            Vector2 dir = (v - m).normalized * speed;
            m.x = m.x.toLine(v.x, dir.x);
            m.y = m.y.toLine(v.y, dir.y);
            return m;
        }

        /// <summary>
        /// 线性平滑到另外一个值
        /// </summary>
        public static Vector3 toLine(this Vector3 m, Vector3 v, float speed)
        {
            Vector3 dir = v - m;
            dir = dir.normalized * speed;
            m.x = m.x.toLine(v.x, dir.x);
            m.y = m.y.toLine(v.y, dir.y);
            m.z = m.z.toLine(v.z, dir.z);
            return m;
        }

        /// <summary>
        /// 获取两个点的2D距离的平方
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static float to2dDis(this Vector3 v1, Vector3 v2)
        {
            return (v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y);
        }

        public static float to2dDis(this Vector2 v1, Vector2 v2)
        {
            return (v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y);
        }

        public static float to2dDis(this Vector2 v1)
        {
            return (v1.x) * (v1.x) + (v1.y) * (v1.y);
        }

        public static float to2dDis(this Vector3 v1)
        {
            return (v1.x) * (v1.x) + (v1.y) * (v1.y);
        }

        public static float toRand(this Vector2 v1)
        {
            return Random.Range(v1.x, v1.y);
        }

        /// 将目标物体从开始点移动到目标点通过平滑的曲线
        ///
        /// 你要移动的目标物体
        /// 目标物体的开始点
        /// 目标物体的结束点
        /// 三个中间点
        /// 你最终得到的路径点的中间数,默认是20,数量越大曲线越平滑,越小越线性
        ///
        public static Vector3[] GetPathPoints(Transform start, Transform end, Transform[] threeCenterPosArr, int needPointNumber = 20)
        {
            //为了节省性能
            //将其转化成;一个float,可以进行差值运算,否则结果为0
            float number = (float)needPointNumber;
            //定义一个数组,用来存放路径点,他的长度是从0 - needPointNumber的长度,及从0-1
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            //只有在等于needPointNumber时Lerp()中最后一项的值才为1,所有比needPointNumber数多1
            for (int i = 0; i <= needPointNumber; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(start.position, threeCenterPosArr[0].position, i / number);
                Vector3 one2 = Vector3.Lerp(threeCenterPosArr[0].position, threeCenterPosArr[1].position, i / number);
                Vector3 one3 = Vector3.Lerp(threeCenterPosArr[1].position, threeCenterPosArr[2].position, i / number);
                Vector3 one4 = Vector3.Lerp(threeCenterPosArr[2].position, end.position, i / number);
                //第二层
                Vector3 two1 = Vector3.Lerp(one1, one2, i / number);
                Vector3 two2 = Vector3.Lerp(one2, one3, i / number);
                Vector3 two3 = Vector3.Lerp(one3, one4, i / number);
                //第三层
                Vector3 three1 = Vector3.Lerp(two1, two2, i / number);
                Vector3 three2 = Vector3.Lerp(two2, two3, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(three1, three2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            //在for循环结束之后得到所有的路径点
            return targetPosArr;
        }

        // 将目标物体从开始点移动到目标点通过平滑的曲线 额外的重载方法,就不仔细介绍了
        public static Vector3[] GetPathPoints(Vector3 startPos, Vector3 endPos, Vector3[] threeCenterPosArr, int needPointNumber = 20)
        {
            float number = (float)needPointNumber;
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            for (int i = 0; i <= number; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(startPos, threeCenterPosArr[0], i / number);
                Vector3 one2 = Vector3.Lerp(threeCenterPosArr[0], threeCenterPosArr[1], i / number);
                Vector3 one3 = Vector3.Lerp(threeCenterPosArr[1], threeCenterPosArr[2], i / number);
                Vector3 one4 = Vector3.Lerp(threeCenterPosArr[2], endPos, i / number);
                //第二层
                Vector3 two1 = Vector3.Lerp(one1, one2, i / number);
                Vector3 two2 = Vector3.Lerp(one2, one3, i / number);
                Vector3 two3 = Vector3.Lerp(one3, one4, i / number);
                //第三层
                Vector3 three1 = Vector3.Lerp(two1, two2, i / number);
                Vector3 three2 = Vector3.Lerp(two2, two3, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(three1, three2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            return targetPosArr;
        }

        #region  多节点路径平滑
        //多节点路径平滑 SmoothSens平滑倍数
        public static Vector3[] PathSmooth(this Vector3[] path, int SmoothSens)
        {
            if (path.Length < 4)
            {
                return path;
            }
            Vector3[] vector3s = PathControlPointGenerator(path);

            int SmoothAmount = path.Length * SmoothSens;
            Vector3[] Vector3list = new Vector3[SmoothAmount];
            for (int i = 1; i <= SmoothAmount; i++)
            {
                float pm = (float)i / SmoothAmount;
                Vector3 currPt = Interp(vector3s, pm);
                Vector3list[i - 1] = currPt;
            }
            return Vector3list;
        }
        private static Vector3[] PathControlPointGenerator(Vector3[] suppliedPath)
        {
            int offset = 2;
            Vector3[] vs = new Vector3[suppliedPath.Length + offset];
            Array.Copy(suppliedPath, 0, vs, 1, suppliedPath.Length);

            vs[0] = vs[1] + (vs[1] - vs[2]);
            vs[vs.Length - 1] = vs[vs.Length - 2] + (vs[vs.Length - 2] - vs[vs.Length - 3]);

            if (vs[1] == vs[vs.Length - 2])
            {
                Vector3[] tmpLoopSpline = new Vector3[vs.Length];
                Array.Copy(vs, tmpLoopSpline, vs.Length);
                tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
                tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
                vs = new Vector3[tmpLoopSpline.Length];
                Array.Copy(tmpLoopSpline, vs, tmpLoopSpline.Length);
            }
            return (vs);
        }

        private static Vector3 Interp(Vector3[] pts, float t)
        {
            int numSections = pts.Length - 3;
            int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
            float u = t * (float)numSections - (float)currPt;

            Vector3 a = pts[currPt];
            Vector3 b = pts[currPt + 1];
            Vector3 c = pts[currPt + 2];
            Vector3 d = pts[currPt + 3];

            return .5f * (
                (-a + 3f * b - 3f * c + d) * (u * u * u)
                + (2f * a - 5f * b + 4f * c - d) * (u * u)
                + (-a + c) * u
                + 2f * b
            );
        }
        #endregion


        //一个额外点的贝萨尔曲线(即抛物线)
        public static Vector3[] GetPathPoints(Vector3 startPos, Vector3 endPos, Vector3 centerPos, int needPointNumber = 20)
        {
            //为了节省性能
            //将其转化成;一个float,可以进行差值运算,否则结果为0
            float number = (float)needPointNumber;
            //定义一个数组,用来存放路径点,他的长度是从0 - needPointNumber的长度,及从0-1
            Vector3[] targetPosArr = new Vector3[needPointNumber + 1];
            //只有在等于needPointNumber时Lerp()中最后一项的值才为1,所有比needPointNumber数多1
            for (int i = 0; i <= needPointNumber; i++)
            {
                //第一层
                Vector3 one1 = Vector3.Lerp(startPos, centerPos, i / number);
                Vector3 one2 = Vector3.Lerp(centerPos, endPos, i / number);
                //目标层
                Vector3 targetPos = Vector3.Lerp(one1, one2, i / number);
                //将目标层放入我们的路径点中
                targetPosArr[i] = targetPos;
            }
            //在for循环结束之后得到所有的路径点
            return targetPosArr;
        }

        /// <summary>
        /// 判断点是否在多边形内.
        /// ----------原理----------
        /// 注意到如果从P作水平向左的射线的话，如果P在多边形内部，那么这条射线与多边形的交点必为奇数，
        /// 如果P在多边形外部，则交点个数必为偶数(0也在内)。
        /// </summary>
        /// <param name="checkPoint">要判断的点</param>
        /// <param name="polygonPoints">多边形的顶点</param>
        /// <returns></returns>
        public static bool IsInPolygon(Vector2 checkPoint, List<Vector2> polygonPoints)
        {
            bool inside = false;
            int pointCount = polygonPoints.Count;
            Vector3 p1, p2;
            for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一个点和最后一个点作为第一条线，之后是第一个点和第二个点作为第二条线，之后是第二个点与第三个点，第三个点与第四个点...
            {
                p1 = polygonPoints[i];
                p2 = polygonPoints[j];
                if (checkPoint.y < p2.y)
                {//p2在射线之上
                    if (p1.y <= checkPoint.y)
                    {//p1正好在射线中或者射线下方
                        if ((checkPoint.y - p1.y) * (p2.x - p1.x) > (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判断,在P1和P2之间且在P1P2右侧
                        {
                            //射线与多边形交点为奇数时则在多边形之内，若为偶数个交点时则在多边形之外。
                            //由于inside初始值为false，即交点数为零。所以当有第一个交点时，则必为奇数，则在内部，此时为inside=(!inside)
                            //所以当有第二个交点时，则必为偶数，则在外部，此时为inside=(!inside)
                            inside = (!inside);
                        }
                    }
                }
                else if (checkPoint.y < p1.y)
                {
                    //p2正好在射线中或者在射线下方，p1在射线上
                    if ((checkPoint.y - p1.y) * (p2.x - p1.x) < (checkPoint.x - p1.x) * (p2.y - p1.y))//斜率判断,在P1和P2之间且在P1P2右侧
                    {
                        inside = (!inside);
                    }
                }
            }
            return inside;
        }




    }

    public static class Const
    {
        //用 |  叠加标记
        //用 ^  去除标记

        ///<summary>Int 设置增减标记 </summary>
        public static T toTagSetI<T>(this Enum a, T b, bool isAdd)
        {
            if (isAdd)
            {
                return a.toTagAddI(b);
            }
            else
            {
                return a.toTagRemoveI(b);
            }
        }

        ///<summary>int 去除标记</summary>
        public static T toTagRemoveI<T>(this Enum a, T b)
        {
            if (a.toTagInI(b))
            {
                T t = (a.GetHashCode() ^ b.GetHashCode()).toEnum<T>();
                return t;
            }
            else
            {
                T t = (T)(object)a;
                return t;
            }
        }

        ///<summary>int 增加标记</summary>
        public static T toTagAddI<T>(this Enum a, T b)
        {
            T t = (a.GetHashCode() | b.GetHashCode()).toEnum<T>();
            return t;
        }

        /// <summary>
        /// 二进制的标记 判断A是否包含B标记
        /// </summary>
        public static bool toTagInI<T>(this Enum a, T b)
        {
            int ia = a.GetHashCode();
            int ib = b.GetHashCode();
            if (ia == ib)
            {
                return true;
            }
            if ((ia & ib) == ib)
            {
                return true;
            }
            return false;
        }

        public static int toTagSetI(this int a, int b, bool isAdd)
        {
            if (isAdd)
            {
                return a.toTagAddI(b);
            }
            else
            {
                return a.toTagRemoveI(b);
            }
        }

        public static int toTagRemoveI(this int a, int b)
        {
            if (a.toTagInI(b))
            {
                int t = (a ^ b);
                return t;
            }
            else
            {
                int t = a;
                return t;
            }
        }

        public static int toTagAddI(this int a, int b)
        {
            int t = a | b;
            return t;
        }

        public static bool toTagInI(this int a, int b)
        {
            int ia = a;
            int ib = b;
            if (ia == ib)
            {
                return true;
            }
            if ((ia & ib) == ib)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 二进制的标记 判断A是否包含B标记,尽量不要循环内使用,如果有需要,直接在外面进行强制类型转换
        /// </summary>
        public static bool toTagInL(this Enum a, Enum b)
        {
            if (a == b)
            {
                return true;
            }
            long ia = a.toLong();
            long ib = b.toLong();
            if ((ia & ib) == ib)
            {
                return true;
            }
            return false;
        }

        public const long LUnit = 1;
        public const int IUnit = 1;

        public const long l1 = LUnit << 1;
        public const long l2 = LUnit << 2;
        public const long l3 = LUnit << 3;
        public const long l4 = LUnit << 4;
        public const long l5 = LUnit << 5;
        public const long l6 = LUnit << 6;
        public const long l7 = LUnit << 7;
        public const long l8 = LUnit << 8;
        public const long l9 = LUnit << 9;
        public const long l0 = LUnit << 0;
        public const long l11 = LUnit << 11;
        public const long l12 = LUnit << 12;
        public const long l13 = LUnit << 13;
        public const long l14 = LUnit << 14;
        public const long l15 = LUnit << 15;
        public const long l16 = LUnit << 16;
        public const long l17 = LUnit << 17;
        public const long l18 = LUnit << 18;
        public const long l19 = LUnit << 19;
        public const long l10 = LUnit << 10;
        public const long l21 = LUnit << 21;
        public const long l22 = LUnit << 22;
        public const long l23 = LUnit << 23;
        public const long l24 = LUnit << 24;
        public const long l25 = LUnit << 25;
        public const long l26 = LUnit << 26;
        public const long l27 = LUnit << 27;
        public const long l28 = LUnit << 28;
        public const long l29 = LUnit << 29;
        public const long l20 = LUnit << 20;
        public const long l31 = LUnit << 31;
        public const long l32 = LUnit << 32;
        public const long l33 = LUnit << 33;
        public const long l34 = LUnit << 34;
        public const long l35 = LUnit << 35;
        public const long l36 = LUnit << 36;
        public const long l37 = LUnit << 37;
        public const long l38 = LUnit << 38;
        public const long l39 = LUnit << 39;
        public const long l30 = LUnit << 30;
        public const long l41 = LUnit << 41;
        public const long l42 = LUnit << 42;
        public const long l43 = LUnit << 43;
        public const long l44 = LUnit << 44;
        public const long l45 = LUnit << 45;
        public const long l46 = LUnit << 46;
        public const long l47 = LUnit << 47;
        public const long l48 = LUnit << 48;
        public const long l49 = LUnit << 49;
        public const long l40 = LUnit << 40;

        public const long l51 = LUnit << 51;
        public const long l52 = LUnit << 52;
        public const long l53 = LUnit << 53;
        public const long l54 = LUnit << 54;
        public const long l55 = LUnit << 55;
        public const long l56 = LUnit << 56;
        public const long l57 = LUnit << 57;
        public const long l58 = LUnit << 58;
        public const long l59 = LUnit << 59;
        public const long l50 = LUnit << 50;

        public const long l61 = LUnit << 61;
        public const long l62 = LUnit << 62;
        public const long l63 = LUnit << 63;
        public const long l64 = LUnit << 64;
        public const long l65 = LUnit << 65;
        public const long l66 = LUnit << 66;
        public const long l67 = LUnit << 67;
        public const long l68 = LUnit << 68;
        public const long l69 = LUnit << 69;
        public const long l60 = LUnit << 60;

        public const long l71 = LUnit << 71;
        public const long l72 = LUnit << 72;
        public const long l73 = LUnit << 73;
        public const long l74 = LUnit << 74;
        public const long l75 = LUnit << 75;
        public const long l76 = LUnit << 76;
        public const long l77 = LUnit << 77;
        public const long l78 = LUnit << 78;
        public const long l79 = LUnit << 79;
        public const long l70 = LUnit << 70;

        public const long l81 = LUnit << 81;
        public const long l82 = LUnit << 82;
        public const long l83 = LUnit << 83;
        public const long l84 = LUnit << 84;
        public const long l85 = LUnit << 85;
        public const long l86 = LUnit << 86;
        public const long l87 = LUnit << 87;
        public const long l88 = LUnit << 88;
        public const long l89 = LUnit << 89;
        public const long l80 = LUnit << 80;

        public const long l91 = LUnit << 91;
        public const long l92 = LUnit << 92;
        public const long l93 = LUnit << 93;
        public const long l94 = LUnit << 94;
        public const long l95 = LUnit << 95;
        public const long l96 = LUnit << 96;
        public const long l97 = LUnit << 97;
        public const long l98 = LUnit << 98;
        public const long l99 = LUnit << 99;
        public const long l90 = LUnit << 90;

        public const long l101 = LUnit << 101;
        public const long l102 = LUnit << 102;
        public const long l103 = LUnit << 103;
        public const long l104 = LUnit << 104;
        public const long l105 = LUnit << 105;
        public const long l106 = LUnit << 106;
        public const long l107 = LUnit << 107;
        public const long l108 = LUnit << 108;
        public const long l109 = LUnit << 109;
        public const long l100 = LUnit << 100;

        //long能到320
        public const int i1 = IUnit << 1;

        public const int i2 = IUnit << 2;
        public const int i3 = IUnit << 3;
        public const int i4 = IUnit << 4;
        public const int i5 = IUnit << 5;
        public const int i6 = IUnit << 6;
        public const int i7 = IUnit << 7;
        public const int i8 = IUnit << 8;
        public const int i9 = IUnit << 9;
        public const int i0 = IUnit << 0;
        public const int i11 = IUnit << 11;
        public const int i12 = IUnit << 12;
        public const int i13 = IUnit << 13;
        public const int i14 = IUnit << 14;
        public const int i15 = IUnit << 15;
        public const int i16 = IUnit << 16;
        public const int i17 = IUnit << 17;
        public const int i18 = IUnit << 18;
        public const int i19 = IUnit << 19;
        public const int i10 = IUnit << 10;
        public const int i21 = IUnit << 21;
        public const int i22 = IUnit << 22;
        public const int i23 = IUnit << 23;
        public const int i24 = IUnit << 24;
        public const int i25 = IUnit << 25;
        public const int i26 = IUnit << 26;
        public const int i27 = IUnit << 27;
        public const int i28 = IUnit << 28;
        public const int i29 = IUnit << 29;
        public const int i20 = IUnit << 20;
        public const int i30 = IUnit << 30;
        public const int i31 = IUnit << 31;
        //int只能到31
    }

    public static class Physics2Dt
    {
        public static RaycastHit2D[] LinecastAll(Vector2 start, Vector2 end, int layerMask, bool isDW = true)
        {

            RaycastHit2D[] hit = Physics2D.LinecastAll(start, end, layerMask);
            if (isDW)
            {
                if (hit.Length > 0)
                {
                    debug.Draw().Line(start, hit[0].point, Color.green);
                    debug.Draw().Line(hit[0].point, end, Color.red);
                }
                else
                {
                    debug.Draw().Line(start, end, Color.green);
                }

                for (int i = 0; i < hit.Length; i++)
                {
                    debug.Draw().Fork(hit[i].point, 0.1f);
                }
            }
            return hit;
        }

        public static RaycastHit2D[] LinecastAll(Transform root, Vector2 start, Vector2 end, int layerMask, bool isDW = true)
        {
            RaycastHit2D[] hit = Physics2D.LinecastAll(start, end, layerMask);
            Mlist<RaycastHit2D> list = new Mlist<RaycastHit2D>();
            for (int i = 0; i < hit.Length; i++)
            {
                if (hit[i].collider)
                {
                    if (!hit[i].transform.IsChildOf(root))
                    {
                        list.Add(hit[i]);
                    }
                }
            }
            if (isDW)
            {
                if (list.Count > 0)
                {
                    debug.Draw().Line(start, list[0].point, Color.green);
                    debug.Draw().Line(list[0].point, end, Color.red);
                }
                else
                {
                    debug.Draw().Line(start, end, Color.green);
                }

                for (int i = 0; i < list.Count; i++)
                {
                    debug.Draw().Fork(list[i].point, 0.1f);
                }
            }
            return list;
        }

        public static RaycastHit2D[] RaycastAll(Vector2 origin, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            var hit = Physics2D.RaycastAll(origin, direction, distance, layerMask);
            if (isDW)
            {
                debug.Draw().Ray(origin, direction, distance);
                for (int i = 0; i < hit.Length; i++)
                {
                    debug.Draw().Fork(hit[i].point, 0.1f);
                }
            }
            return hit;
        }
        //排除自己的子节点
        public static RaycastHit2D[] RaycastAllExcludeChild(Transform root, Vector2 origin, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            RaycastHit2D[] hit = Physics2D.RaycastAll(origin, direction, distance, layerMask);
            Mlist<RaycastHit2D> list = new Mlist<RaycastHit2D>();
            for (int i = 0; i < hit.Length; i++)
            {
                if (hit[i].collider)
                {
                    if (!hit[i].transform.IsChildOf(root))
                    {
                        list.Add(hit[i]);
                    }
                }
            }
            if (isDW)
            {
                debug.Draw().Ray(origin, direction, distance);
                for (int i = 0; i < list.Count; i++)
                {
                    debug.Draw().Fork(list[i].point, 0.1f);
                }
            }
            return list;
        }

        public static RaycastHit2D Raycast(Vector2 origin, Vector2 direction, float distance, int layerMask, Color color, bool isDW = true)
        {
            var hit = Physics2D.Raycast(origin, direction, distance, layerMask);
            if (isDW)
            {
                if (hit)
                {
                    debug.Draw().Ray(origin, direction, hit.distance, Color.green);
                    debug.Draw().Ray(hit.point, direction, distance - hit.distance, Color.red);
                }
                else
                {
                    debug.Draw().Ray(origin, direction, distance);
                }
            }
            return hit;
        }

        public static RaycastHit2D Raycast(Vector2 origin, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            return Raycast(origin, direction, distance, layerMask, Color.red, isDW);
        }

        public static RaycastHit2D Raycast(Vector2 origin, Vector2 direction, float distance, bool isDW = true)
        {
            var hit = Physics2D.Raycast(origin, direction, distance);
            if (isDW)
            {
                if (hit)
                {
                    debug.Draw().Ray(origin, direction, hit.distance, Color.green);
                    debug.Draw().Ray(hit.point, direction, distance - hit.distance, Color.green);
                }
                else
                {
                    debug.Draw().Ray(origin, direction, distance);
                }
            }
            return hit;
        }

        public static RaycastHit2D[] RaycastAll(Vector2 origin, Vector2 direction, float distance, bool isDW = true)
        {
            if (isDW)
            {
                debug.Draw().Ray(origin, direction, distance);
            }
            return Physics2D.RaycastAll(origin, direction, distance);
        }

        public static RaycastHit2D[] BoxCastAll(Vector2 origin, Vector2 size, float angle, Vector2 direction, float distance, bool isDW = true)
        {
            RaycastHit2D[] hitarr = Physics2D.BoxCastAll(origin, size, angle, direction, distance);
            if (isDW)
            {
                debug.Draw().Box(origin, size, angle, Color.blue);
                debug.Draw().Box(origin + direction.normalized * distance, size, angle, Color.yellow);
                for (int i = 0; i < hitarr.Length; i++)
                {
                    var hit = hitarr[i];
                    if (hit)
                    {
                        debug.Draw().Fork(hit.point, Color.green, 0.1f);
                        debug.Draw().Box(hit.centroid, size, angle);
                    }
                }
            }
            return hitarr;
        }

        public static RaycastHit2D[] BoxCastAll(Vector2 origin, Vector2 size, float angle, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            RaycastHit2D[] hitarr = Physics2D.BoxCastAll(origin, size, angle, direction, distance, layerMask);
            if (isDW)
            {
                debug.Draw().Box(origin, size, angle, Color.blue);
                debug.Draw().Box(origin + direction.normalized * distance, size, angle, Color.yellow);
                for (int i = 0; i < hitarr.Length; i++)
                {
                    var hit = hitarr[i];
                    if (hit)
                    {
                        debug.Draw().Fork(hit.point, Color.green, 0.1f);
                        debug.Draw().Box(hit.centroid, size, angle);
                    }
                }
            }
            return hitarr;
        }

        public static RaycastHit2D BoxCast(Vector2 origin, Vector2 size, float angle, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            RaycastHit2D hit = Physics2D.BoxCast(origin, size, angle, direction, distance, layerMask);
            if (isDW)
            {
                debug.Draw().Box(origin, size, angle, Color.blue);
                debug.Draw().Box(origin + direction.normalized * distance, size, angle, Color.yellow);

                if (hit)
                {
                    debug.Draw().Fork(hit.point, Color.green, 0.1f);
                    debug.Draw().Box(hit.centroid, size, angle);
                }
            }

            return hit;
        }

        public static RaycastHit2D CircleCast(Vector2 origin, float radius, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            if (isDW)
            {
                debug.Draw().Circle(origin + direction.normalized * distance, radius);
            }
            return Physics2D.CircleCast(origin, radius, direction, distance, layerMask);
        }

        public static RaycastHit2D[] CircleCastAll(Vector2 origin, float radius, Vector2 direction, float distance, int layerMask, bool isDW = true)
        {
            var hit = Physics2D.CircleCastAll(origin, radius, direction, distance, layerMask);
            if (isDW)
            {
                if (hit.Length > 0)
                {
                    debug.Draw().Circle(origin, radius, radius / 21, Color.green);
                    for (int i = 0; i < hit.Length; i++)
                    {
                        debug.Draw().Line(origin, hit[i].point, Color.green);
                    }
                }
                else
                {
                    debug.Draw().Circle(origin, radius, radius / 21, Color.yellow);
                }
            }
            return hit;
        }

        public static RaycastHit2D[] CircleCastAll(Vector2 origin, float radius, Vector2 direction, float distance, bool isDW = true)
        {
            if (isDW)
            {
                debug.Draw().Circle(origin + direction.normalized * distance, radius);
            }
            return Physics2D.CircleCastAll(origin, radius, direction, distance);
        }
        /// <summary>
        /// 去除本对象所有的碰撞盒的碰撞
        /// </summary>
        /// <param name="tf"></param>
        public static void toIgnoreCollision2D(this Transform tf)
        {
            var coll = tf.GetComponentsInChildren<Collider2D>();
            for (int i = 0; i < coll.Length; i++)
            {
                for (int j = 0; j < coll.Length; j++)
                {
                    Physics2D.IgnoreCollision(coll[i], coll[j]);
                }
            }
        }
    }
}